/*
 *  Borum, Boolean rule manipulator.
 *  Copyright (C) 2009 Jon Lennersten, Johan Hedin, Daniel Rosenberg
 *
 *  This file is part of Borum.
 *
 *  Borum is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Borum is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with Borum.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.mawell.borum;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.basic.BasicSplitPaneDivider;
import javax.swing.plaf.basic.BasicSplitPaneUI;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

public class MultiView extends JPanel {

    private MultiModel multiModel;

    private Translation trans;

    private JSplitPane splitPane;
    private JList viewList;

    JLabel deleteLabel;
    JLabel copyLabel;

    JPopupMenu viewListMenu;
    JPopupMenu viewListUndeleteMenu;

    Object translationForTerms;

    private MyCellRenderer cellRenderer = new MyCellRenderer(false);

    public MultiView(MultiModel multiModel, List<OperandProperty> possibleProperties, java.util.List<Term> possibleTerms, Translation trans, Object translationForTerms) {
        this.multiModel = multiModel;
        this.trans = trans;
        this.translationForTerms = translationForTerms;
        multiModel.setPossibleTerms(possibleTerms);
        multiModel.setPossibleProperties(possibleProperties);
        this.setLayout(new GridBagLayout());
        init();

        viewList.setSelectedIndex(multiModel.getViewListModel().size() - 1);
        int pos = splitPane.getDividerLocation();
        setRightComponent();
        splitPane.setDividerLocation(pos);
    }

    public MultiView(List<OperandProperty> possibleProperties, List<Term> possibleTerms, Translation trans, Object translationForTerms) {
        this(new MultiModel(), possibleProperties, possibleTerms, trans, translationForTerms);
    }

    public boolean isSingleSelection() {
        return cellRenderer.isSingleSelection();
    }

    public void setSingleSelection(boolean singleSelection) {
        cellRenderer.setSingleSelection(singleSelection);
    }

    public java.util.List<Rule> getRules() {

        ArrayList<Rule> rules = new ArrayList<Rule>();
        DefaultListModel list = multiModel.getViewListModel();
        Enumeration e = list.elements();
        while(e.hasMoreElements()) {
            RuleView view = (RuleView) e.nextElement();        
            rules.add(view.getRule());
        }

        return rules;
    }

    public void loadRule(Rule rule) {
        RuleView rView = new RuleView(rule, trans, multiModel.getPossibleProperties(), multiModel.getPossibleTerms(), translationForTerms);
        rView.expandAll(true);
        
        multiModel.addRuleView(rView);
    }


    public static void flattenSplitPane(JSplitPane jSplitPane) {
        jSplitPane.setUI(new BasicSplitPaneUI() {
            public BasicSplitPaneDivider createDefaultDivider() {
                return new BasicSplitPaneDivider(this) {
                    public void setBorder(Border b) {
                    }
                };
            }
        });
        jSplitPane.setBorder(null);
    }

    private void init() {
        splitPane = new JSplitPane();
        getLeftComponent();
        setRightComponent();
        flattenSplitPane(splitPane);

        splitPane.setContinuousLayout(true);
        GridBagConstraints c = new GridBagConstraints();
        c.anchor = GridBagConstraints.NORTHWEST;
        c.weightx = 1; // add horizontal space to this component
        c.weighty = 1; // add vertical space to this component
        c.gridwidth = GridBagConstraints.REMAINDER; // end of row
        c.gridheight = 1;
        c.fill = GridBagConstraints.BOTH; // fill vertically and horizontally if bigger than expected

        this.add(splitPane, c);
    }

    private void getLeftComponent() {
        JPanel leftPanel = new JPanel(new GridBagLayout());

        GridBagConstraints c = new GridBagConstraints();
        c.anchor = GridBagConstraints.NORTHWEST;
        c.weightx = 0; // add horizontal space to this component
        c.weighty = 0; // add vertical space to this component
        c.gridwidth = GridBagConstraints.REMAINDER; // end of row
        c.gridheight = 1;
        c.fill = GridBagConstraints.NONE; // fill vertically and horizontally if bigger than expected
        leftPanel.add(addButtons(), c);

        c = new GridBagConstraints();
        c.anchor = GridBagConstraints.NORTHWEST;
        c.weightx = 1; // add horizontal space to this component
        c.weighty = 1; // add vertical space to this component
        c.gridwidth = GridBagConstraints.REMAINDER; // end of row
        c.gridheight = 1;
        c.fill = GridBagConstraints.BOTH; // fill vertically and horizontally if bigger than expected
        leftPanel.add(addListArea(), c);

        splitPane.setLeftComponent(leftPanel);
    }

    private Component addButtons() {
        JPanel buttonPanel = new JPanel();

        java.net.URL url = MultiView.class.getResource("/icons/add.png");
        ImageIcon imageIcon = new ImageIcon(url);
        JLabel addLabel = new JLabel(imageIcon);
        addLabel.setToolTipText(trans.getLabelAdd());
        addLabel.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                RuleModel model = new RuleModel();
                model.setPossibleTerms(multiModel.getPossibleTerms());
                model.setPossibleProperties(multiModel.getPossibleProperties());
                RuleView rView = new RuleView(model, trans);
                rView.setName(trans.getLabelNewRule());
                rView.setNewRule(true);
                multiModel.addRuleView(rView);

                setSelectedIndex(multiModel.getViewListModel().size() - 1);
                int pos = splitPane.getDividerLocation();
                setRightComponent();
                splitPane.setDividerLocation(pos);
            }
        });
        buttonPanel.add(addLabel);

        url = MultiView.class.getResource("/icons/delete.png");
        imageIcon = new ImageIcon(url);
        deleteLabel = new JLabel(imageIcon);
        deleteLabel.setToolTipText(trans.getLabelDelete());
        deleteLabel.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if(deleteLabel.isEnabled()) {
                    multiModel.deleteRuleView(viewList.getSelectedIndex());
                    viewList.repaint();
                }
            }
        });
        deleteLabel.setEnabled(false);
        buttonPanel.add(deleteLabel);

        url = MultiView.class.getResource("/icons/page_copy.png");
        imageIcon = new ImageIcon(url);
        copyLabel = new JLabel(imageIcon);
        copyLabel.setToolTipText(trans.getLabelCopy());
        copyLabel.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if(copyLabel.isEnabled()) {
                    RuleView copy = new RuleView(multiModel.getView(viewList.getSelectedIndex()));
                    copy.setNewRule(true);
                    multiModel.addRuleView(copy);
                    setSelectedIndex(multiModel.getViewListModel().size() - 1);
                    int pos = splitPane.getDividerLocation();
                    setRightComponent();
                    splitPane.setDividerLocation(pos);
                }
            }
        });
        copyLabel.setEnabled(false);
        buttonPanel.add(copyLabel);

        return buttonPanel;
    }

    private void setSelectedIndex(int i) {
        viewList.setSelectedIndex(i);
        if(isSingleSelection()) {
            if(multiModel.getView(i) != null && !multiModel.getView(i).isLocked()) {
                for(int j = 0; j < multiModel.viewListModel.getSize(); j++) {
                    multiModel.getView(j).setSelected(false);
                }
                multiModel.getView(i).setSelected(!multiModel.getView(i).isSelected());
            }
            repaint();
        }

    }

    private Component addListArea() {
        viewListMenu = new JPopupMenu();

        final JMenuItem renameItem = new JMenuItem(trans.getLabelRename());
        renameItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0));
        renameItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                renameRuleView();
            }
        });
        viewListMenu.add(renameItem);

        final JMenuItem deleteItem = new JMenuItem(trans.getLabelDelete());
        deleteItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
        deleteItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                multiModel.deleteRuleView(viewList.getSelectedIndex());
            }
        });
        viewListMenu.add(deleteItem);

        viewListUndeleteMenu = new JPopupMenu();

        final JMenuItem undeleteItem = new JMenuItem(trans.getLabelUndelete());
        undeleteItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                multiModel.undeleteRuleView(viewList.getSelectedIndex());
            }
        });
        viewListUndeleteMenu.add(undeleteItem);


        viewList = new JList(multiModel.getViewListModel());
        viewList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        viewList.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if(!e.getValueIsAdjusting()) {
                    int pos = splitPane.getDividerLocation();
                    setRightComponent();
                    splitPane.setDividerLocation(pos);
                    if(multiModel.getView(viewList.getSelectedIndex()) == null) {
                        deleteLabel.setEnabled(false);
                        copyLabel.setEnabled(false);
                    } else {
                        copyLabel.setEnabled(true);
                        if(multiModel.getView(viewList.getSelectedIndex()).isLocked()) {
                            deleteLabel.setEnabled(false);
                        } else {
                            deleteLabel.setEnabled(true);
                        }
                    }
                }
            }
        });


        viewList.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                if(e.getButton() == MouseEvent.BUTTON1) {
                    int idx = viewList.locationToIndex(e.getPoint());
                    setSelectedIndex(idx);
                }

            }

            @Override
            public void mouseReleased(MouseEvent e) {
                if(e.getButton() == MouseEvent.BUTTON3) {
                    int idx = viewList.locationToIndex(e.getPoint());
                    viewList.setSelectedIndex(idx);
                }
                if(viewListMenu.isPopupTrigger(e)) {
                    RuleView selectedView = multiModel.getView(viewList.getSelectedIndex());
                    if(selectedView.isDeleted()) {
                        viewListUndeleteMenu.show(e.getComponent(), e.getX(), e.getY());
                    } else {
                        if(selectedView.isLocked()) {
                            renameItem.setEnabled(false);
                            deleteItem.setEnabled(false);
                        } else {
                            renameItem.setEnabled(true);
                            deleteItem.setEnabled(true);
                        }
                        viewListMenu.show(e.getComponent(), e.getX(), e.getY());
                    }
                }
            }
        });
        viewList.setCellRenderer(cellRenderer);

        viewList.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), "F2");
        AbstractAction renameAction = new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                if(multiModel.getView(viewList.getSelectedIndex()) != null) {
                    renameRuleView();
                }
            }
        };
        viewList.getActionMap().put("F2", renameAction);

        viewList.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), "DELETE");
        AbstractAction deleteAction = new AbstractAction() {
            public void actionPerformed(ActionEvent e) {
                if(multiModel.getView(viewList.getSelectedIndex()) != null) {
                    multiModel.deleteRuleView(viewList.getSelectedIndex());
                    viewList.repaint();
                }
            }
        };
        viewList.getActionMap().put("DELETE", deleteAction);
        return new JScrollPane(viewList);
    }

    private void renameRuleView() {
        if(multiModel.getView(viewList.getSelectedIndex()).isLocked()) {
            return;
        }
        String s = (String) JOptionPane.showInputDialog(
                viewList,
                null,
                trans.getLabelRename(),
                JOptionPane.PLAIN_MESSAGE,
                null,
                null,
                multiModel.getView(viewList.getSelectedIndex()).getName());
        if(s != null) {
            multiModel.setRuleViewName(s, viewList.getSelectedIndex());
        }
    }

    private void setRightComponent() {
        RuleView selectedView = multiModel.getView(viewList.getSelectedIndex());
        if(selectedView == null) {
            JLabel emptyText = new JLabel("<html>" + trans.getLabelSelectARule());
            JPanel centerPanel = new JPanel(new GridBagLayout());
            GridBagConstraints c = new GridBagConstraints();
            c.anchor = GridBagConstraints.CENTER;
            c.weightx = 0; // add horizontal space to this component
            c.weighty = 0; // add vertical space to this component
            c.gridwidth = GridBagConstraints.REMAINDER; // end of row
            c.gridheight = 1;
            c.fill = GridBagConstraints.NONE; // fill vertically and horizontally if bigger than expected

            centerPanel.add(emptyText, c);
            centerPanel.setBorder(null);
            splitPane.setRightComponent(centerPanel);
        } else {
            splitPane.setRightComponent(selectedView);
        }
    }

}
